#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#include <errno.h>
#include <limits.h>
#define MAX_TRAINS 100

#define MAX_PASSENGERS 1000

#define FILENAME_TRAINS "trains.dat"

#define FILENAME_PASSENGERS "passengers.dat"


typedef struct {
    
	char train_no[20];      // 车次
    
	char start_station[50]; // 始发站
    
	char end_station[50];   // 终点站
    
	char depart_time[10];   // 发车时间
    
	char arrive_time[10];   // 到达时间
    
	float price;           // 票价
    
	int total_seats;       // 总座位数
    
	int available_seats;   // 剩余座位数

} Train;


typedef struct {
    
	char train_no[20];      // 车 
    
	char name[50];          // 乘客姓名
    
	char id[20];            // 身份证号
    
	char phone[15];         // 电话号码

	} Passenger;

Train trains
[MAX_TRAINS];
Passenger passengers
[MAX_PASSENGERS];

int train_count = 0;

int passenger_count = 0;


// 从文件加载数据

void load_data() {
    FILE *file;
    
    
// 加载火车信息
    file = fopen(FILENAME_TRAINS, "rb");
    
if (file != NULL) {
        train_count = fread(trains, sizeof(Train), MAX_TRAINS, file);
        
	fclose(file);
    
}
    
    
// 加载乘客信息
    file = fopen(FILENAME_PASSENGERS, "rb");
    
if (file != NULL) {
        passenger_count = fread(passengers, sizeof(Passenger), MAX_PASSENGERS, file);
        
		fclose(file);
    
}

}


// 保存数据到文件

void SaveTraininfo() {
    FILE *file;
    
    
// 保存火车信息
    file = fopen(FILENAME_TRAINS, "wb");
    
if (file != NULL) {
        
fwrite(trains, sizeof(Train), train_count, file);
        
fclose(file);
    
}
    
    
// 保存乘客信息
    file = fopen(FILENAME_PASSENGERS, "wb");
    
if (file != NULL) {
        
	fwrite(passengers, sizeof(Passenger), passenger_count, file);
        
	fclose(file);
    
}

}

// 验证身份证号函数
int validateID(const char *id) {
    if (strlen(id) != 18) return 0;
    for (int i = 0; i < 17; i++) {
        if (!isdigit(id[i])) return 0;
    }
    char last = id[17];
    return isdigit(last) || (last == 'X') || (last == 'x');
}

// 验证电话号码函数
int validatePhone(const char *phone) {
    if (strlen(phone) != 11) return 0;
    if (phone[0] != '1' || phone[1] < '3' || phone[1] > '9') return 0; // 第二位3-9
    for (int i = 0; i < 11; i++) {
        if (!isdigit(phone[i])) return 0;
    }
    return 1;
}

// 添加火车信息（已添加输入时返回功能）

void Traininfo() { 
    
	if (train_count >= MAX_TRAINS) {
        
	printf("火车信息已满，无法添加!\n");
        
	return;
    
}
    
    Train new_train;
    
	printf("\n--- 添加火车信息（输入0可随时返回）---\n");
    
    
	printf("请输入车次（输入0返回）: ");
    
	scanf("%s", new_train.train_no);
    
	if (strcmp(new_train.train_no, "0") == 0) {
        
	printf("操作已取消。\n");
        
	return;
    
}
    
    
// 检查车次是否已存在
    
	for (int i = 0; i < train_count; i++) {
        
	if (strcmp(trains[i].train_no, new_train.train_no) == 0) {
            
	printf("该车次已存在!\n");
            
	return;
        
}
    
}
    
    
	printf("请输入始发站（输入0返回）: ");
    
	scanf("%s", new_train.start_station);
    
	if (strcmp(new_train.start_station, "0") == 0) {
        
	printf("操作已取消。\n");
        
	return;
    
}
    
    
	printf("请输入终点站（输入0返回）: ");
    
	scanf("%s", new_train.end_station);
    
	if (strcmp(new_train.end_station, "0") == 0) {
        
	printf("操作已取消。\n");
        
	return;
    
}
    
    
	int c;
	while ((c = getchar()) != '\n' && c != EOF); // 清空输入缓冲区

	while (1) {
    	printf("请输入发车时间(HH:MM)（输入0返回）: ");
    	fgets(new_train.depart_time, sizeof(new_train.depart_time), stdin);
    		new_train.depart_time[strcspn(new_train.depart_time, "\n")] = '\0'; // 去除换行符

    if (strcmp(new_train.depart_time, "0") == 0) {
        printf("操作已取消。\n");
        return;
    }

    // 格式检查：长度5且第三个字符为冒号
    if (strlen(new_train.depart_time) != 5 || new_train.depart_time[2] != ':') {
        printf("错误：时间格式应为HH:MM。\n");
        continue;
    }

    // 数字字符验证
    int valid = 1;
    for (int i = 0; i < 2; i++) {
        if (!isdigit((unsigned char)new_train.depart_time[i])) {
            valid = 0;
            break;
        }
    }
    for (int i = 3; i < 5; i++) {
        if (!isdigit((unsigned char)new_train.depart_time[i])) {
            valid = 0;
            break;
        }
    }
    if (!valid) {
        printf("错误：小时和分钟必须为数字。\n");
        continue;
    }

    // 数值转换与验证
    char original_colon = new_train.depart_time[2];
    new_train.depart_time[2] = '\0';
    int hour = atoi(new_train.depart_time);
    new_train.depart_time[2] = original_colon;

    int minute = atoi(&new_train.depart_time[3]);

    if (hour < 0 || hour > 23) {
        printf("错误：小时必须在00到23之间。\n");
        continue;
    }
    if (minute < 0 || minute > 59) {
        printf("错误：分钟必须在00到59之间。\n");
        continue;
    }

    break; // 验证通过退出循环
}
    
while (1) {
        printf("请输入到达时间(HH:MM)（输入0返回）: ");
        fgets(new_train.arrive_time, sizeof(new_train.arrive_time), stdin);
        new_train.arrive_time[strcspn(new_train.arrive_time, "\n")] = '\0'; // 去除换行符
if (strcmp(new_train.arrive_time, "0") == 0) {
        
printf("操作已取消。\n");
        
return;
    
}
        // 检查格式：长度5且第三个字符为冒号
        if (strlen(new_train.arrive_time) != 5 || new_train.arrive_time[2] != ':') {
            printf("错误：时间格式应为HH:MM。\n");
            continue;
        }

        // 验证小时和分钟部分均为数字
        int hour, minute;
        int valid = 1;
        for (int i = 0; i < 2; i++) {
            if (!isdigit((unsigned char)new_train.arrive_time[i])) {
                valid = 0;
                break;
            }
        }
        for (int i = 3; i < 5; i++) {
            if (!isdigit((unsigned char)new_train.arrive_time[i])) {
                valid = 0;
                break;
            }
        }
        if (!valid) {
            printf("错误：小时和分钟必须为数字。\n");
            continue;
        }

        // 提取并转换小时和分钟
        char original_colon = new_train.arrive_time[2];
		new_train.arrive_time[2] = '\0';
		hour = atoi(new_train.arrive_time);
		new_train.arrive_time[2] = original_colon;

		minute = atoi(&new_train.arrive_time[3]);


        // 验证数值范围
        if (hour < 0 || hour > 23) {
            printf("错误：小时必须在00到23之间。\n");
            continue;
        }
        if (minute < 0 || minute > 59) {
            printf("错误：分钟必须在00到59之间。\n");
            continue;
        }

        break; // 输入有效，退出循环
    }
    

    

    
    
printf("请输入票价（输入0返回）: ");
    
char price_input[20];
    
scanf("%s", price_input);
    
if (strcmp(price_input, "0") == 0) {
        
printf("操作已取消。\n");
        
return;
    
}
    new_train.price = atof(price_input);
    
    
while (1) {  // 循环直到输入有效或取消
        printf("请输入总座位数（输入0返回）: ");
        
        char seats_input[20];
        if (scanf("%19s", seats_input) != 1) {  // 处理输入失败
            printf("输入读取错误，请重试。\n");
            while (getchar() != '\n');  // 清空输入缓冲区
            continue;
        }

        // 检查是否取消操作
        if (strcmp(seats_input, "0") == 0) {
            printf("操作已取消。\n");
            return;
        }

        char *endptr;
        errno = 0;
        long seats = strtol(seats_input, &endptr, 10);  // 转换为长整型

        // 验证输入合法性
        if (*endptr != '\0') {
            printf("错误：输入包含非数字字符，请重新输入。\n");
        } else if (errno == ERANGE || seats > INT_MAX || seats <= 0) {
            printf("错误：请输入1到%d之间的正整数。\n", INT_MAX);
        } else {
            int total_seats = (int)seats;
            new_train.total_seats = atoi(seats_input);
    		new_train.available_seats = new_train.total_seats;
    
    		trains[train_count++] = new_train;
            printf("成功设置座位数为：%d\n", total_seats);
            break;  // 输入有效，退出循环
        }
    }
    
    
SaveTraininfo();
    
printf("火车信息添加成功!\n");

}


// 显示所有火车信息（无需修改）

void showtrain() {
    printf("\n--- 所有火车信息 ---\n");
    printf("车次\t始发站\t终点站\t发车时间\t到达时间\t票价\t剩余座位\n");
    
    for (int i = 0; i < train_count; i++) {
        printf("%s\t%s\t%s\t%s    \t%s    \t%.2f\t%d\n", 
               trains[i].train_no, 
               trains[i].start_station, 
               trains[i].end_station,
               trains[i].depart_time,
               trains[i].arrive_time,
               trains[i].price,
               trains[i].available_seats);
    }
}



// 按车次查询（已添加返回功能）

void search_by_train_no() {
    
char train_no[20];
    
printf("\n请输入要查询的车次（输入0返回）: ");
    
scanf("%s", train_no);
    
if (strcmp(train_no, "0") == 0) {
        
printf("操作已取消。\n");
        
return;
    
}
    
    
printf("\n--- 查询结果 ---\n");
    printf("车次\t始发站\t终点站\t发车时间\t到达时间\t票价\t剩余座位\n");
    
    int found = 0;
    for (int i = 0; i < train_count; i++) {
        if (strcmp(trains[i].train_no, train_no) == 0) {
            printf("%s\t%s\t%s\t%s    \t%s    \t%.2f\t%d\n", 
                   trains[i].train_no, 
                   trains[i].start_station, 
                   trains[i].end_station,
                   trains[i].depart_time,
                   trains[i].arrive_time,
                   trains[i].price,
                   trains[i].available_seats);
            found = 1;
            break;
        }
    }
    
    if (!found) {
        printf("未找到该车次信息!\n");
    }
}




// 按城市查询（已添加返回功能）

void search_by_city() {
    
char city[50];
    
printf("\n请输入要查询的城市（输入0返回）: ");
    
scanf("%s", city);
    
if (strcmp(city, "0") == 0) {
        
printf("操作已取消。\n");
        
return;
    
}
    
    
printf("\n--- 查询结果 ---\n");
    printf("车次\t始发站\t终点站\t发车时间\t到达时间\t票价\t剩余座位\n");
    
    int found = 0;
    for (int i = 0; i < train_count; i++) {
        if (strcmp(trains[i].start_station, city) == 0 || 
            strcmp(trains[i].end_station, city) == 0) {
            printf("%s\t%s\t%s\t%s    \t%s    \t%.2f\t%d\n", 
                   trains[i].train_no, 
                   trains[i].start_station, 
                   trains[i].end_station,
                   trains[i].depart_time,
                   trains[i].arrive_time,
                   trains[i].price,
                   trains[i].available_seats);
            found = 1;
        }
    }
    
    if (!found) {
        printf("未找到该城市的车次信息!\n");
    }
}





// 订票（已添加返回功能）

void bookticket() {
    
char train_no[20];
    
printf("\n--- 订票（输入0可随时返回）---\n");
    
printf("请输入要预订的车次（输入0返回）: ");
    
scanf("%s", train_no);
    
if (strcmp(train_no, "0") == 0) {
        
printf("操作已取消。\n");
        
return;
    
}
    
    
int train_index = -1;
    for (int i = 0; i < train_count; i++) {
        if (strcmp(trains[i].train_no, train_no) == 0) {
            train_index = i;
            break;
        }
    }
    
    if (train_index == -1) {
        printf("未找到该车次信息!\n");
        return;
    }
    
    if (trains[train_index].available_seats <= 0) {
        printf("该车次已无余票!\n");
        return;
    }
    
    Passenger new_passenger;
    strcpy(new_passenger.train_no, train_no);
    
    printf("请输入乘客姓名: ");
    scanf("%s", new_passenger.name);
    // 在输入时进行验证
	printf("请输入身份证号: ");
	do {
    	scanf("%18s", new_passenger.id);
    // 清除输入缓冲区多余字符
    	int c;
    	while ((c = getchar()) != '\n' && c != EOF);
    	if (!validateID(new_passenger.id)) {
        	printf("身份证号格式错误，请重新输入: ");
    	}
	} while (!validateID(new_passenger.id));

	printf("请输入电话号码: ");
	do {
    	scanf("%11s", new_passenger.phone);
    // 清除输入缓冲区多余字符
    	int c;
    while ((c = getchar()) != '\n' && c != EOF);
    if (!validatePhone(new_passenger.phone)) {
        printf("电话号码格式错误，请重新输入: ");
    }
	} while (!validatePhone(new_passenger.phone));

	// 数据合理后保存
	
    
    passengers[passenger_count++] = new_passenger;
    trains[train_index].available_seats--;
    
    SaveTraininfo();
    printf("\n订票成功!\n");
    printf("车次: %s\n", train_no);
    printf("乘客: %s\n", new_passenger.name);
    printf("身份证: %s\n", new_passenger.id);
    printf("电话: %s\n", new_passenger.phone);
}




// 修改火车信息（已增强返回功能）

void Modify() {
    
char train_no[20];
    
printf("\n--- 修改火车信息（输入0可随时返回）---\n");
    
printf("请输入要修改的车次（输入0返回）: ");
    
scanf("%s", train_no);
    
if (strcmp(train_no, "0") == 0) {
        
printf("操作已取消。\n");
        
return;
    
}
    
    
int train_index = -1;
    for (int i = 0; i < train_count; i++) {
        if (strcmp(trains[i].train_no, train_no) == 0) {
            train_index = i;
            break;
        }
    }
    
    if (train_index == -1) {
        printf("未找到该车次信息!\n");
        return;
    }
    
    printf("\n当前信息:\n");
    printf("车次: %s\n", trains[train_index].train_no);
    printf("1. 始发站: %s\n", trains[train_index].start_station);
    printf("2. 终点站: %s\n", trains[train_index].end_station);
    printf("3. 发车时间: %s\n", trains[train_index].depart_time);
    printf("4. 到达时间: %s\n", trains[train_index].arrive_time);
    printf("5. 票价: %.2f\n", trains[train_index].price);
    printf("6. 总座位数: %d\n", trains[train_index].total_seats);
    
    printf("\n请选择要修改的项目(1-6, 0取消): ");
    int choice;
    scanf("%d", &choice);
    
    switch (choice) {
        case 0:
            return;
        case 1:
            printf("请输入新的始发站: ");
            scanf("%s", trains[train_index].start_station);
            break;
        case 2:
            printf("请输入新的终点站: ");
            scanf("%s", trains[train_index].end_station);
            break;
        case 3:
            printf("请输入新的发车时间(HH:MM): ");
            scanf("%s", trains[train_index].depart_time);
            break;
        case 4:
            printf("请输入新的到达时间(HH:MM): ");
            scanf("%s", trains[train_index].arrive_time);
            break;
        case 5:
            printf("请输入新的票价: ");
            scanf("%f", &trains[train_index].price);
            break;
        case 6:
            printf("请输入新的总座位数: ");
            scanf("%d", &trains[train_index].total_seats);
            // 调整剩余座位数
            if (trains[train_index].available_seats > trains[train_index].total_seats) {
                trains[train_index].available_seats = trains[train_index].total_seats;
            }
            break;
        default:
            printf("无效的选择!\n");
            return;
    }
    
    SaveTraininfo();
    printf("修改成功!\n");
}



// 显示菜单
void show_menu() {
    printf("\n=== 火车票订票系统 ===\n");
    printf("1. 添加火车信息\n");
    printf("2. 显示所有火车信息\n");
    printf("3. 按车次查询\n");
    printf("4. 按城市查询\n");
    printf("5. 订票\n");
    printf("6. 修改火车信息\n");
    printf("0. 退出系统\n");
    printf("请选择: ");
}

int main() {
    load_data();
    
    int choice;
    do {
        show_menu();
        scanf("%d", &choice);
        
        switch (choice) {
            case 1:
                Traininfo();
                break;
            case 2:
                showtrain();
                break;
            case 3:
                search_by_train_no();
                break;
            case 4:
                search_by_city();
                break;
            case 5:
                bookticket();
                break;
            case 6:
                Modify();
                break;
            case 0:
                printf("感谢使用火车票订票系统，再见!\n");
                break;
            default:
                printf("无效的选择，请重新输入!\n");
        }
    } while (choice != 0);
    
    return 0;
}